#include <stdio.h>
#include <stdlib.h>

typedef int ElemSet; /* 默认元素为整数*/

ElemSet *TwoWayMerge(ElemSet *a, int l_x, int r_x, int l_y, int r_y) {
    int i, j, k, n;
    ElemSet *t;

    n = (r_x - l_x + 1) + (r_y - l_y + 1); /* 两个序列元素的总个数 */
    t = (ElemSet *)malloc(sizeof(ElemSet) * n); /* 创建临时数组 */
    i = l_x;
    j = l_y;
    k = 0;
    while (i <= r_x || j <= r_y) {
        if (j > r_y || (i <= r_x && a[i] <= a[j])) {
            t[k] = a[i]; /* 将a[i]添加至t末尾 */
            i++;
        } else {
            t[k] = a[j]; /* 将a[j]添加至t末尾 */
            j++;
        }
        k++;
    }
    return t;
}

int Min(int x, int y) {
    return (x < y) ? x : y;
}

/* 算法10-10：自底向上的归并排序 MergeSortBottomUp(a,l,r) */
void MergeSortBottomUp(ElemSet *a, int l, int r) {
    int sorted_len, n, l_x, r_x, l_y, r_y, i;
    ElemSet *t;

    sorted_len = 1; /* 当前有序子列长度 */
    n = r - l + 1; /* 待排元素个数，即序列长度 */
    while (sorted_len <
            n) { /* 当前有序子列长度小于序列长度，则相邻两子序列归并 */
        l_x = l; /* 左子序列从最左端开始 */
        while (l_x <= (r - sorted_len)) {
            r_x = l_x + sorted_len - 1; /* 左子序列的右端点 */
            l_y = r_x + 1; /* 右子序列的左端点 */
            r_y = Min(l_y + sorted_len - 1, r); /* 右子序列的右端点 */
            t = TwoWayMerge(a, l_x, r_x, l_y, r_y); /* 归并 */
            for (i = l_x; i <= r_y; i++) { /* 将归并后的有序序列t复制回a中 */
                a[i] = t[i - l_x];
            }
            l_x = r_y + 1; /* 下一对子序列的左子序列的左端点 */
        }
        sorted_len <<= 1; /* 有序子列长度加倍 */
    }
}
/* 算法10-10 结束 */

int main(void) {
    ElemSet *a; /* 数组a的下标从0开始 */
    int n, i;

    scanf("%d", &n);
    a = (ElemSet *)malloc(sizeof(ElemSet) * n);
    for (i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    MergeSortBottomUp(a, 0, n - 1);
    for (i = 0; i < n; i++) {
        printf("%d ", a[i]);
    }

    return 0;
}